<?php

namespace adminmatrix\plugin\command;

use Symfony\Component\Process\Exception\LogicException;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\console\helper\ProgressBar;
use think\console\Table;
use think\facade\Console;

class Install extends Command
{
    protected string $pluginName;
    protected array $pluginInfo;
    protected string $path;

    protected $usleep = 10000;

    protected array $install = [];
    protected function configure()
    {
        $this->setName("plugin:install")
            ->addOption("--plugin" ,"-p" , 3 , "要安装的插件名称")
            ->setDescription("插件安装");
//        parent::configure(); // TODO: Change the autogenerated stub
    }

    protected function execute(Input $input, Output $output)
    {
        if (!$input->hasOption("plugin"))
            throw new LogicException("插件名称不能为空 --plugin=插件名 或者 -p 插件名称");

        $pluginName =  $this->pluginName = $input->getOption("plugin");
        if (is_null($pluginName))
            throw new LogicException("插件名称不能为空 --plugin=插件名 或者 -p 插件名称");

        # 判断插件是否存在
        $path = $this->path = $this->app->getRootPath() . "plugins/$pluginName";
        if (!file_exists($path))
            throw new LogicException(sprintf("插件 %s 不存在" , $pluginName) );

        $config = $path . "/config.json";
        if (!file_exists($config))
            throw new LogicException(sprintf("插件 %s 中缺少配置文件 %s " , $pluginName  , $config) );
        $pluginInfo = $this->pluginInfo  = json_decode( file_get_contents($config) , true);

        if ($pluginInfo['status'])
            throw new LogicException(sprintf("插件 %s 已经安装过了" , $pluginName));

        $output->info(sprintf("准备执行安装插件 -> %s" , $pluginInfo['name']));
//        return parent::execute($input, $output); // TODO: Change the autogenerated stub

        $this->output = $output;

        $this->install();
        $output->info("\n完成！");
    }

    # 检测环境
    protected function install(){

//        # 检查版本
        $this->checkVersion();
//
//        # 检查是否需要安装依赖
        $this->checkComposer();

        # 检测是否需要安装数据库
        $this->checkDataBase();

        # 执行安装脚本
        $this->ProgressBar();
//        halt($this->install);

        # 执行最后操作
//        $this->modifyConfigJson($this->path . "/config.json" , 'status' , true);
    }

    # 检查版本
    protected function checkVersion(){
        $this->output->warning("正在检查版本请稍后...");
        usleep($this->usleep);
        # 检测插件版本
        $version = $this->pluginInfo['version'] ?? '';
        if ($version)
        {
            $this->output->writeln("当前插件版本:{$version}");
        }else{
            $this->output->warning("暂无该插件版本");
        }
        usleep($this->usleep);
    }

    # 检查依赖包
    protected function checkComposer(){

        $this->output->warning("正在检查composer...");
        usleep($this->usleep);
        # 检测是否需要安装composer
        if (file_exists($this->path . "/composer.json"))
        {
            $table = new Table();

            $this->output->info("检测到有需要安装的插件");

            $table = new Table();
            $table->setHeader(['插件名称', '插件版本']);
            $composer = json_decode(file_get_contents($this->path . "/composer.json"), true);

            foreach ($composer as $key => $value) {
                $table->addRow([$key?? '', $value ?? '']);
            }

            echo $table->render();

            $this->install["composer"] =  $composer;

        }
        usleep($this->usleep);

    }

    protected function checkDataBase(){
        $this->output->warning("正在检查是否需要安装数据");
        usleep($this->usleep);
        $table = new Table();
        $table->setStyle('box');
        $table->setHeader(['版本号', '所属插件' , "安装名称"] , 2);
        $datas = glob($this->path . "/database/migrations" . "/*.php");
        if (count($datas) == 0)
        {
            $this->output->info("无需安装数据库");
        }else{
            $this->output->info("需要安装的数据表如下:");
            foreach (glob($this->path . "/database/migrations" . "/*.php") as $value)
            {
                $pathInfo = pathinfo($value);
                $database = explode("_",$pathInfo['filename']);

                $version = array_shift($database);
                array_shift($database);
                $pluginName = array_shift($database);
                $name       =   array_shift($database);
                $table->addRow([$version        ,$pluginName ?? '-',$name??'-']);

            }

            echo $table->render();
            usleep($this->usleep);

            if ($this->output->confirm($this->input , "是否需要安装"))
            {
                $this->install['database'] = true;
            }
        }
        $rootPath = $this->app->getRootPath();

        $cmd = 'php think plugin:migrate_run ceshi';
        $proc = proc_open($cmd, [
            1 => ['pipe', 'w'],
            2 => ['pipe', 'w'],
        ], $pipes, $rootPath);

        if (is_resource($proc)) {
            while (!feof($pipes[1]) || !feof($pipes[2])) {
                if (!feof($pipes[1])) {
                    $line = fgets($pipes[1]);
                    if ($line !== false) {
                        echo $line;
                        flush();
                    }
                }
                if (!feof($pipes[2])) {
                    $line = fgets($pipes[2]);
                    if ($line !== false) {
                        echo $line;
                        flush();
                    }
                }
            }
            fclose($pipes[1]);
            fclose($pipes[2]);
            proc_close($proc);
        }
    }



    protected function modifyConfigJson($filePath, $field, $newValue) {
        $this->output->writeln("正在执行最后操作");
        try {
            // 检查文件是否存在
            if (!file_exists($filePath)) {
                throw new LogicException("文件 $filePath 不存在。");
            }

            // 读取 JSON 文件内容
            $jsonContent = file_get_contents($filePath);
            if ($jsonContent === false) {
                throw new Exception("无法读取文件 $filePath。");
            }

            // 解码 JSON 数据
            $data = json_decode($jsonContent, true);
            if ($data === null) {
                throw new Exception("无法解码 JSON 数据。");
            }

            // 修改指定字段的值
            if (array_key_exists($field, $data)) {
                $data[$field] = $newValue;
            } else {
                throw new Exception("字段 $field 不存在于 JSON 文件中。");
            }

            // 编码修改后的数据为 JSON 格式
            $newJsonContent = json_encode($data, JSON_PRETTY_PRINT);
            if ($newJsonContent === false) {
                throw new Exception("无法编码 JSON 数据。");
            }

            // 将修改后的数据写回到文件中
            if (file_put_contents($filePath, $newJsonContent) === false) {
                throw new Exception("无法将修改后的数据写入文件 $filePath。");
            }

            return true;
        } catch (Exception $e) {
            $this->output->error($e->getMessage());
            return false;
        }
    }

    protected function ProgressBar()
    {
        $pluginComposerFile = $this->path . '/composer.json';
        if (file_exists($pluginComposerFile)) {
            $pluginComposer = json_decode(file_get_contents($pluginComposerFile), true);
            $rootPath = $this->app->getRootPath();

            foreach ($pluginComposer as $package => $version) {
                $cmd = 'composer require ' . escapeshellarg(trim($package)) . ':' . escapeshellarg(trim($version)) . ' --no-interaction --ansi';
                $proc = proc_open($cmd, [
                    1 => ['pipe', 'w'],
                    2 => ['pipe', 'w'],
                ], $pipes, $rootPath);

                if (is_resource($proc)) {
                    while (!feof($pipes[1]) || !feof($pipes[2])) {
                        if (!feof($pipes[1])) {
                            $line = fgets($pipes[1]);
                            if ($line !== false) {
                                echo $line;
                                flush();
                            }
                        }
                        if (!feof($pipes[2])) {
                            $line = fgets($pipes[2]);
                            if ($line !== false) {
                                echo $line;
                                flush();
                            }
                        }
                    }
                    fclose($pipes[1]);
                    fclose($pipes[2]);
                    proc_close($proc);
                }
            }
        }
    }

    protected function runWithProgressBar($cmd, $desc = '正在执行', $workDir = null)
    {
        $barLength = 50;
        $lineLength = 120;
        $percent = 0;
        $bar = '';
        $progressBar = '';
        $outputLines = [];
        $totalLines = 20; // 估算输出行数

        echo "\n"; // 先输出一行给进度条

        $proc = proc_open($cmd, [
            1 => ['pipe', 'w'],
            2 => ['pipe', 'w'],
        ], $pipes, $workDir);

        $lastOutputTime = time();

        if (is_resource($proc)) {
            while (true) {
                $line = '';
                $hasNewOutput = false;
                $status = proc_get_status($proc);

                if (!feof($pipes[1])) {
                    $line = fgets($pipes[1]);
                }
                if ($line === false && !feof($pipes[2])) {
                    $line = fgets($pipes[2]);
                }
                if ($line !== false) {
                    $line = trim($line);
                    if ($line !== '') {
                        $outputLines[] = $line;
                        // 输出日志
                        echo $line . "\n";
                        // 上移一行，准备刷新进度条
                        echo "\033[1A";
                        $hasNewOutput = true;
                        $lastOutputTime = time();
                    }
                }

                // 进度条按输出行数估算
                $percent = min(100, intval(count($outputLines) / $totalLines * 100));
                // 如果长时间无新输出，自动缓慢推进进度条
                if (!$hasNewOutput && $percent < 95) {
                    if (time() - $lastOutputTime > 1) {
                        $percent += 1;
                        $lastOutputTime = time();
                    }
                }
                $barCount = intval($percent / 100 * $barLength);
                $bar = str_repeat('#', $barCount) . str_repeat(' ', $barLength - $barCount);
                $progressBar = sprintf("%s: [%s] %3d%%", $desc, $bar, $percent);

                // 刷新进度条（覆盖当前行）
                echo "\r" . str_pad($progressBar, $lineLength, ' ') . "\033[K";
                flush();
                usleep(100000);

                // 检查子进程是否已结束
                if (!$status['running']) {
                    break;
                }
            }
            fclose($pipes[1]);
            fclose($pipes[2]);
            proc_close($proc);
        }

        // 安装完成，显示最后一行和100%进度
        $percent = 100;
        $bar = str_repeat('#', $barLength);
        $progressBar = sprintf("%s: [%s] %3d%%", $desc, $bar, $percent);
        echo "\r" . str_pad($progressBar, $lineLength, ' ') . "\033[K\n";
        flush();
        usleep(500000);
    }
}